#include "Renderer_PCH.h"
#include "RBuffer.h"

/*--------------------------------------------------------------------------*/

RBuffer::RBuffer(uint size, bool dynamic, GLenum type) :
	m_size(size),
	m_dynamic(dynamic),
	m_type(type),
	m_data(NULL),
	m_handle(0),
	m_mutex(NULL)
{
	glGenBuffers(1, &m_handle);
	__Check(m_handle);
	glBindBuffer(type, m_handle);
	glBufferData(type, size, NULL, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);

	m_data = new uchar[size];
	__Check(m_data);

	m_mutex = g_Kernel->CreateNewMutex();
	__Check(m_mutex);
}

/*--------------------------------------------------------------------------*/

RBuffer::~RBuffer()
{
	if (m_handle)
	{
		glDeleteBuffers(1, &m_handle);
	}

	delete m_mutex;
}

/*--------------------------------------------------------------------------*/

uchar* RBuffer::Lock( uint size, uint offset )
{
	m_mutex->Lock();
	__Check(m_size > size);
	__Check(m_size > size + offset);

	if (size == 0)
	{
		return NULL;
	}

	m_updatedLocations.push_back(MemoryLocation(size, offset));
	return &m_data[offset];
}

/*--------------------------------------------------------------------------*/

uint RBuffer::GetSize() const
{
	return m_size;
}

/*--------------------------------------------------------------------------*/

bool RBuffer::IsDynamic() const
{
	return m_dynamic;
}

/*--------------------------------------------------------------------------*/

uint RBuffer::GetHandle()
{
	return m_handle;
}

/*--------------------------------------------------------------------------*/

void RBuffer::Flush()
{
	__Check(m_handle);
	glBindBuffer(m_type, m_handle);

	for (auto iter = m_updatedLocations.begin(); iter != m_updatedLocations.end(); ++iter)
	{
		__Check(iter->m_offset < m_size);
		__Check(iter->m_offset + iter->m_size < m_size);

		glBufferSubData(m_type, iter->m_offset, iter->m_size, &m_data[iter->m_offset]);
	}

	glBindBuffer(m_type, 0);

	m_updatedLocations.clear();
	m_mutex->Unlock();
}

/*--------------------------------------------------------------------------*/

MemoryLocation::MemoryLocation( uint size, uint offset ) :
	m_size(size),
	m_offset(offset)

{

}

/*--------------------------------------------------------------------------*/